The Italian CRaCKiNG Encyclopedia  vol. 4
                       -------------------------------
                          -------------------------
                             Making KeyGenerator
                               ---------------
                                  ---------
                                     ---

                                  Scritto da 

                              ---==: ALoR :==--- 
                 ---==>  Proud member of NEURO ZONE 2  <==---

                                 Dicembre 1998



                                 Target = ****

   (*=Lamer, **=Novizio, ***=Apprendista, ****=Esperto, *****=CrackMaster)


==============================================================================

Table of context :

1.0  Disclaimer.
2.0  I tools necessari.
3.0  Prerequisiti.
4.0  Intro.
5.0  Analisi del codice.
6.0  Scrittura di un keymaker.


7.0  Conclusioni

==============================================================================


-----------------
 1.0  DISCLAIMER
-----------------

Every reference to facts, things or persons (virtual, real or esoteric) are 
purely casual and involuntary. Any trademark nominated here is registered or 
copyright of their respective owners. The author of this manual does not 
assume any responsability on the content or the use of informations retriven 
from here; he makes no guarantee of correctness, accuracy, reliability, safety
or performance. This manual is provided "AS IS" without warranty of any kind.
You alone are fully responsible for determining if this page is safe for use 
in your environment and for everything you are doing with it! 


Ormai lo saprete a memoria.....ma mi � necessario per pararmi il culo !!!



------------------------
 2.0  I TOOLS NECESSARI
------------------------

Per produrre un Generatore di Serial # sono necessari:

     * W32Dasm 8.9 or higher
     * Soft-Ice 3.2 or higher
     * Un compilatore ad alto livello (C, C++, ecc.)
     

-------------------
 3.0  PREREQUISITI
-------------------

E' necessario che conosciate almeno le basi dell'assembler. Intendo almeno
le istruzioni add, mul, div, mov, push, pop, call, jmp... ecc.
Se volete distribuire il vostro keygenerator dovrete creare un programma che
sia in grado di elaborare l'username e che produca un codice adeguato.
Per fare questo dovreste conoscere almeno un linguaggio ad alto livello (C,
C++, Pascal, ecc..).


------------
 4.0  INTRO
------------

Sempre piu' spesso i programmatori di shareware o trialware si affidano alla
rete per diffondere i propri programmi. Per potersi registrare e' necessario
(almeno loro credono :) pagare una somma di denaro alla casa produttrice che
ti fornira' il codice magico univoco e intestato solo a te.
Nasce quindi il key generator... un programmino che ti permette di avere il
tuo nome nel campo User: della licenza del tuo programmino preferito, e senza
aver pagato nemmeno una lira :)
Il bello del keygen e' proprio qui. Quando e' finito puoi sfornare quanti 
codici ti pare !! (es. User: Micro$oft Sucks  Key: xxxxxxxxxxxx :)
Un altro vantaggio del keygen sta nel fatto che il codice del prg. non e'
alterato. Questa e' un ottima cosa, specialmente negli ultimi tempi i prg. si
auto controllano (con CRC e menate varie) per vedere se sono stati modificati.
In conclusione il keygen e' il modo migliore per crackare un prg. semplice da
usare (non tanto da fare... argh..), pulito e poi fa un sacco figo :)


-------------------------
 5.0  ANALISI DEL CODICE 
-------------------------

Nel vol. 3 abbiamo scoperto come trovare il codice giusto in una zona di
memoria. Ma non potete certo ripetere la procedura ogni volta che vi serve
un User nuovo....
Impareremo ora a crearci il keymaker per Winzip 6.3 (andra' bene anche per
tutte le ver precedenti e anche per la 7.0).
Disassembliamo l'eseguibile (ho scelto la ver 6.3 in modo che una parte dell
analisi e' gia' stata discussa nel vol. 3) e cominciamo.

Vi ricordate... eravamo arrivati a scoprire che:


    
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004097C6(C)                                                      
|                                                                  
:004097DE  lea eax, dword ptr [ebp+FFFFFDF8]    
:004097E4  push eax
:004097E5  push 00471258                        <-- indirizzo del nome
:004097EA  call 004098C3                        <-- calcolo codice
:004097EF  pop ecx
:004097F0  pop ecx                              <-- provate "d ECX" :-)
:004097F1  push 0046F578                        <-- vi ricordate cos'era ?...
:004097F6  lea eax, dword ptr [ebp+FFFFFDF8]    <-- in questo istante EBP
                                                 contiene 0012F950. +FFFFFDF8
                                                 in complemento a 16 � -208.
                                                 Quindi st� mettendo in EAX
                                                 qualcosa che si trova all'
                                                 indirizzo 0012F748. Cosa ci 
                                                 sar� mai a quell'indirizzo.:)
:004097FC  push eax
:004097FD  call 004465D0                        <-- parametri passati:
                                                    0046F578  il nostro codice
                                                    EAX       il codice giusto
:00409802  pop ecx
:00409803  pop ecx


Ora la parte piu' succosa non e' piu' "d ECX" oppure "d 0012F748" dove si 
trova il codice, bensi' la call 004098C3 che calcola il codice esatto.
Dovremo quindi analizzare la routine all'indirizzo 004098C3 e tradurla in un
linguaggio ad alto livello per creare il nostro keygen.

Mettetevi comodi, carta, penna, martini, mooolta pazienza... Let's go... 

Allora... ecco la procedura con un po di analisi a margine...


* Referenced by a CALL at Address:
|:004097EA   
|
:004098C3    push ebp
:004098C4    mov ebp, esp
:004098C6    sub esp, 00000010
:004098C9    and word ptr [ebp-0C], 0000          ebp-0C = 0          2^Half
:004098CE    and word ptr [ebp-08], 0000          ebp-08 = 0          1^Half
:004098D3    mov eax, dword ptr [ebp+08]             eax = username
:004098D6    mov dword ptr [ebp-04], eax          ebp-04 = username
:004098D9    and word ptr [ebp-10], 0000          ebp-10 = 0
:004098DE    jmp 004098F3


Fondamentalmente inizializzazione delle variabili. ebp-0c rappresenta la zona
di memoria dove sara' allocata la seconda parte del codice, ebp-08 sara' per 
la prima. Infatti il codice e' formato da due numeri esadecimali da 4 
caratteri ciascuno. Ci aiuta a scoprirlo la stringa "%04X%04X" (per chi si 
intende di C) Vedi sotto dove e' utilizzata.


* Referenced by 00409915(U)
|
:004098E0    mov ax, word ptr [ebp-10]        \
:004098E4    add ax, 0001                      | count = count + 1
:004098E8    mov word ptr [ebp-10], ax        /
:004098EC    mov eax, dword ptr [ebp-04]      \  username[count]
:004098EF    inc eax                           | 
:004098F0    mov dword ptr [ebp-04], eax      /  ALoR --> LoR --> oR --> R

* Referenced by 004098DE(U)
|
:004098F3    mov eax, dword ptr [ebp-04]      \ 
:004098F6    movzx eax, byte ptr [eax]         | if username[count] == 0  
:004098F9    test eax, eax                     |                jmp fine_loop
:004098FB    je 00409917                      / 
:004098FD    mov eax, dword ptr [ebp-04]         eax = username
:00409900    movzx eax, byte ptr [eax]           eax = username[count]
:00409903    movzx ecx, word ptr [ebp-10]        ecx = count
:00409907    imul eax, ecx                       eax = username[count] * count
:0040990A    mov cx, word ptr [ebp-0C]        \
:0040990E    add cx, ax                        | 2^Half = 2^Half + ax
:00409911    mov word ptr [ebp-0C], cx        /
:00409915    jmp 004098E0                     LOOP 


Queste linee di codice costituiscono il loop per la creazione della seconda
parte del codice.
ebp-10 sara' in nostro counter. ebp-04 l'username. ebp-0c la parte di codice
ATTENZIONE: quando si calcola 2^Half = 2^Half + ax bisogna tenere presente che
qui si opera su registri a 16 bit (ax, cx) e non a 32 bit (eax, ecx).



* Referenced by 004098FB(C)
|
:00409917    mov dword ptr [00471C5C], 00000001   <-- Ma serve ?? imho NO :)
:00409921    mov eax, dword ptr [ebp+08]          eax = username
:00409924    mov dword ptr [ebp-04], eax       ebp-04 = username
:00409927    jmp 00409930

* Referenced by 00409956(U)
|
:00409929    mov eax, dword ptr [ebp-04]      \  username[count]
:0040992C    inc eax                           |
:0040992D    mov dword ptr [ebp-04], eax      /  ALoR --> LoR --> oR --> R

* Referenced by 00409927(U)
|
:00409930    mov eax, dword ptr [ebp-04]      \ 
:00409933    movzx eax, byte ptr [eax]         | if username[count] == 0 
:00409936    test eax, eax                     |                 jmp fine_loop
:00409938    je 00409958                      / 
:0040993A    push 00001021                               stack 0x1021 
:0040993F    mov eax, dword ptr [ebp-04]         eax = username
:00409942    movzx ax, byte ptr [eax]            eax = username[count]
:00409946    push eax                                    stack username[count]
:00409947    push [ebp-08]                               stack 1^Half
:0040994A    call 00409980                               CALL calcola --->
:0040994F    add esp, 0000000C                   esp = esp + C 
:00409952    mov word ptr [ebp-08], ax           1^Half = ax
:00409956    jmp 00409929                     LOOP


Loop per il calcolo della prima parte di codice (la piu' complicata).
ATTENZIONE: il vero calcolo e' effettuato dalla CALL 00409980. e i suoi 
parametri gli sono passati attraverso le PUSH.
Quindi i suoi parametri saranno: 0x1021, username[count] e 1^Half
Il ritorno e' messo in ax



* Referenced by 00409938(C)
|
:00409958    mov ax, word ptr [ebp-08]        \  
:0040995C    add ax, 0063                      | 1^Half = 1^Half + 0x63 
:00409960    mov word ptr [ebp-08], ax        / 
:00409964    movzx eax, word ptr [ebp-0C]        eax = 2^Half
:00409968    push eax                                         stack 2^Half
:00409969    movzx eax, word ptr [ebp-08]        eax = 1^Half
:0040996D    push eax                                         stack 1^Half

* Possible StringData Ref from Data Obj ->"%04X%04X"
                                  |
:0040996E    push 00463954                                    stack "%04X%04X"
:00409973    push [ebp+0C]                                    stack ebp+0C
:00409976    call 004452E0                                    CALL 004452E0
:0040997B    add esp, 00000010                   esp = esp + 10
:0040997E    leave
:0040997F    ret                                 END



Parte finale. Aggiunge 0x63 alla prima parte (okkio ai 16 bit) e unisce le due
parti producendo un numero della forma: %04X%04X  es: 11aa0220.


Analizziamo ora il calcolo della prima parte di codice :


* Referenced by a CALL at Addresses:
|:0040994A   , :00409ACB   
|
:00409980   push ebp
:00409981   mov ebp, esp
:00409983   push ecx
:00409984   mov ax, word ptr [ebp+0C]        \  
:00409988   shl ax, 08                        | lettera = username[count] << 8
:0040998C   mov word ptr [ebp+0C], ax        /  
:00409990   and dword ptr [ebp-04], 00000000    i = 0
:00409994   jmp 0040999D


Prende i parametri dallo stack e inizializza il counter (ebp-04).
Il parametro username[count] (qui ebp+0C) e' shiftato a sinistra di 8, cioe'
moltiplicato per 0x100 (256).



* Referenced by 004099DE(U)
|
:00409996   mov eax, dword ptr [ebp-04]         \  
:00409999   inc eax                              | i = i + 1
:0040999A   mov dword ptr [ebp-04], eax         /  

* Referenced by 00409994(U)
|
:0040999D   cmp dword ptr [ebp-04], 00000008    | if (i < 8) jmp fine_call
:004099A1   jge 004099E0                        |
:004099A3   movzx eax, word ptr [ebp+08]          eax = 1^Half
:004099A7   movzx ecx, word ptr [ebp+0C]          ecx = lettera
:004099AB   xor eax, ecx                          eax = temp ^ lettera
:004099AD   and eax, 00008000                     eax = eax & 8000
:004099B2   test eax, eax                       | if (eax == 0) jmp 004099C8
:004099B4   je 004099C8                         | else {
:004099B6   movzx eax, word ptr [ebp+08]             eax = 1^Half
:004099BA   shl eax, 1                               eax = eax << 1
:004099BC   movzx ecx, word ptr [ebp+10]             ecx = 0x1021
:004099C0   xor eax, ecx                             eax = eax ^ 0x1021
:004099C2   mov word ptr [ebp+08], ax                1^Half = ax
:004099C6   jmp 004099D3                        | }


In questo istante ebp+10 e' il parametro passato 0x1021. Attenzione ai soliti
16 bit. La costruzione dell'if non e' palese... ma ci si arriva.


* Referenced by 004099B4(C)
|
:004099C8   mov ax, word ptr [ebp+08]           \ 
:004099CC   shl ax, 1                            | 1^Half = 1^Half << 1
:004099CF   mov word ptr [ebp+08], ax           / 

* Referenced by 004099C6(U)
|
:004099D3   mov ax, word ptr [ebp+0C]           \ 
:004099D7   shl ax, 1                            | lettera = lettera << 1
:004099DA   mov word ptr [ebp+0C], ax           / 
:004099DE   jmp 00409996                     LOOP

* Referenced by 004099A1(C)
|
:004099E0   mov ax, word ptr [ebp+08]             ax = ebp+08
:004099E4   leave
:004099E5   ret                              END


Fine della procedura e ritorno del codice in ax (16 bit).


------------------------------
 6.0 SCRITTURA DI UN KEYMAKER
------------------------------

Dopo aver analizzato a fondo la procedura in linguaggio assembly l'80% del
lavoro e' ormai compiuto. Ora bastera' tradurre, con qualche accorgimento, il
codice assembly in uno ad alto livello quale il C o il C++ e il gioco e' fatto

Ancora qualche sforzo... siamo in dirittura d'arrivo...

un altro martini e via...

Tralascio qui la scrittura del main e dell'input dell'username. Trattero' solo
le due procedure di calcolo delle rispettive parti di codice.


*** Procedura calcolo seconda parte ***


long km2(char *User)
{
long code"2.class" tppabs="http://www.crackstore.com/tutorz/2.class" = 0;                                           /* ebp-0C */
int count = 0;                                            /* ebp-10 */
long lettera;

for (count = 0; count < strlen(User); count++) {          /* LOOP */
   lettera = User[count];
   lettera *= count;
   code2 += lettera;
}

return code2;	
}



*** Procedura calcolo prima parte ***

long km1(char *User)
{
long code1 = 0;                                           /* ebp-10 */
long temp = 0;
int i, count = 0;                                         /* ebp-04 */
int lettera;


for (count = 0; count < strlen(User); count++) {
   lettera = User[count];
   lettera <<= 8;    

   for(i = 0; i < 8; i++) {
      temp = code2;
      temp ^= lettera;
      temp &= 0x8000;
      
      if (temp == 0) { 
         code2 <<= 17;                               /* shift a 16 bit */
         code2 >>= 16;
      } else {	
         code2 <<= 17;                               /* shift a 16 bit */
         code"2.class" tppabs="http://www.crackstore.com/tutorz/2.class" >>= 16;
         code2 ^= 0x1021;
      }
      lettera <<= 17;                                /* shift a 16 bit */	
      lettera >>= 16;
   } 
}

code2 += 0x63;

return code2;	
}


ATTENZIONE: per effettuare lo shift di 1 a sinistra a 16 bit su una variabile
a 32 bit. Ho shiftato di 16 + 1 a sinistra e successivamente di 16 a destra.

esempio:

      var16:      1234   ==        var32:  0000 1234
 var16 << 1:      2340   !=   var32 << 1:  0001 2340
     
                              var32 << 17: 2340 0000
 var16 << 1:      2340   ==   var32 >> 16: 0000 2340
 


Ecco fatto !! We reached the goal !!!
Dopo una dura battaglia e la bottiglia del martini ormai vuota, la testa che
gira sotto effetto dell'alcool... Il nostro keymaker e' pronto.



------------------
 7.0  CONCLUSIONI
------------------

Per il momento non ho idee su come continuare l'enciclopedia. Quindi se avete
suggerimenti per il vol 5 contattatemi pure via mail ALoR@thepentagon.com
Per avere eventuali future release di questo manuale scrivete a: nz2@usa.net


              "If you give a man a crack he'll be hungry again
               tomorrow, but if you teach him how to crack, he'll
               never be hungry again"
                                                 +ORC


       .-.                                                         .-.
      /   \           .-.                           .-.           /   \
     /     \         /   \       .-.     .-.       /   \         /     \
 ---/-------\-------/-----\-----/---\---/---\-----/-----\-------/-------\---
   /         \     /       \   /     `-'     \   /       \     /         \
  /           \   /         `-'               `-'         \   /           \
 /             `-'                                         `-'             \

Greetings to:   LordKasKo  (my cracking teacher...)


                The other NEURO ZONE 2 members (10t8or, DK2DEnd, LordKasKo,
                                                MaPHas, Ob1, XXXX, ZenGa)

                All the Cracker on the NET from whom I have learned something.

==============================================================================

               .________   ._ 
              /  .__    ) /  /      .________   ._____  
             /  (___)  / /  /      /  .__    ) /  ._  ) ..: .    .   .      .
            /  .___   / /  /      /  /   )  / /  / /_/ .. : : .         . 
           /  /   /  / /  /____  /  /___/  / /  /    :: .:: . . .    .  
          (__/   (__/ (________)(_________/ (__/   .:. : . :  .   .    .
 
            --==> ALoR <==---------------------- -  -   - 
                                  ICQ: 10666678    In IRC: WhiteFly

          e-mail: ALoR@thepentagon.com     www: http://ALoR.home.ml.org
                                                http://ALoR.cjb.net

==============================================================================